package com.EAIPClub.CodeLab.CodeIde.service.impl;

import com.EAIPClub.CodeLab.CodeIde.service.CodeIdeService;
import com.api.API.CodeLab.CodeIdeManager.CodeIdeManagerAPI;
import com.api.API.UserAuthDataManager.UserAuthDataManagerAPI;
import com.api.API.UserDataManager.UserDataManagerAPI;
import com.api.ConstantPool;
import com.api.POJO.CodeLab.CodeIde.CodeIdeInfo;
import com.api.POJO.CodeLab.CodeIde.CodeIdeInventedPlatformTokenEntity;
import com.api.POJO.CodeLab.CodeIde.CodeIdeReturnMsg;
import com.api.POJO.CodeLab.CodeIdeDispatchingCenter.CodeIdeDispatchingCenterInfo;
import com.api.POJO.CodeLab.CodeIdeManager.CodeIdeAccount;
import com.api.POJO.CodeLab.CodeIdeManager.CodeIdeManagerReturnMsg;
import com.api.POJO.UserAuthDataManager.UserAuthDataManagerReturnMsg;
import com.api.POJO.UserDataManager.Result.UserDataReturnMsg;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Random;

/**
 * @Description :CodeIde业务逻辑实现
 * @Author :崔昌赫
 * @Date : 2021/10/27
 */

@Service
@Slf4j
public class CodeIdeServiceImpl implements CodeIdeService {

    private CodeIdeManagerAPI managerAPI;

    @Autowired
    public void setManagerAPI(CodeIdeManagerAPI managerAPI) {
        this.managerAPI = managerAPI;
    }

    private UserAuthDataManagerAPI authDataManagerAPI;

    @Autowired
    public void setDataManagerAPI(UserAuthDataManagerAPI authDataManagerAPI) {
        this.authDataManagerAPI = authDataManagerAPI;
    }

    private UserDataManagerAPI userDataManagerAPI;

    @Autowired
    public void setUserDataManagerAPI(UserDataManagerAPI userDataManagerAPI) {
        this.userDataManagerAPI = userDataManagerAPI;
    }

    private RabbitTemplate rabbitTemplate;

    @Autowired
    public void setRabbitTemplate(RabbitTemplate rabbitTemplate) {
        this.rabbitTemplate = rabbitTemplate;
    }

    @Autowired
    public void setAuthDataManagerAPI(UserAuthDataManagerAPI authDataManagerAPI) {
        this.authDataManagerAPI = authDataManagerAPI;
    }

    private final RestTemplate restTemplate = new RestTemplate();
    private final String baseUrl="";


    @Override
    public CodeIdeReturnMsg loginCodeIde(String token) {
        CodeIdeReturnMsg returnMsg = new CodeIdeReturnMsg();
        List<String> Msg = new ArrayList<>();
        log.info("即将登陆codeide.token:{}",token);
        UserAuthDataManagerReturnMsg userAuthDataByToken = authDataManagerAPI.getUserAuthDataByToken(token);
        log.info("通过token获取到用户信息:{}",userAuthDataByToken);
        if(userAuthDataByToken==null || !userAuthDataByToken.getStatus().equals(ConstantPool.OK)){
            log.warn("获取用户信息失败!返回信息:{}",userAuthDataByToken);
            returnMsg.setStatus(ConstantPool.BadRequest);
            Msg.add("获取用户信息失败!");
            returnMsg.setMsg(Msg);
            return returnMsg;
        }
        String uid = userAuthDataByToken.getAuthData().getUid();
        log.info("获取到用户uid:{}",uid);
        if(uid == null || uid.equals("")){
            log.warn("获取用户uid失败!uid:{}",uid);
            returnMsg.setStatus(ConstantPool.BadRequest);
            Msg.add("获取用户uid失败!");
            returnMsg.setMsg(Msg);
            return  returnMsg;
        }
        UserDataReturnMsg userPrivilegesByUid = userDataManagerAPI.findUserPrivilegesByUid(uid);
        log.info("通过uid获取用户权限信息.uid:{},权限信息:{}",uid,userPrivilegesByUid);
        if (userPrivilegesByUid==null||!userPrivilegesByUid.getStatus().equals(ConstantPool.OK)){
            log.warn("通过uid获取用户权限信息失败!uid:{},权限信息:{}",uid,userPrivilegesByUid);
            Msg.add("通过用户uid获取用户权限信息失败!");
            returnMsg.setStatus(ConstantPool.BadRequest);
            returnMsg.setMsg(Msg);
            return returnMsg;
        }
        Integer codeIde = userPrivilegesByUid.getUserPrivileges().getCodeIde();
        log.info("获取用户(uid:{})的codeide权限信息为:{}",uid,codeIde);
        if (codeIde==null){
            log.warn("获取用户(uid:{})的codeide权限信息失败!",uid);
            Msg.add("获取用户的codeide权限信息失败!");
            returnMsg.setStatus(ConstantPool.BadRequest);
            returnMsg.setMsg(Msg);
            return returnMsg;
        }
        if(codeIde==0||codeIde>=2){
            log.warn("用户(uid:{})权限验证错误!权限:{}",uid,codeIde);
            Msg.add("您无权使用codeide!请联系管理员!");
            returnMsg.setStatus(ConstantPool.Unauthorized);
            returnMsg.setMsg(Msg);
            return returnMsg;
        }
        CodeIdeManagerReturnMsg codeIdeInfo = managerAPI.getCodeIdeInfo(uid);
        log.info("获取用户(uid:{})codeide信息:{}",uid,codeIdeInfo);
        if(codeIdeInfo==null || !codeIdeInfo.getStatus().equals(ConstantPool.OK)){
            log.info("未获取到用户(uid:{})的codeide信息!",uid);
            Msg.add("未获取到用户codeide信息!");
            returnMsg.setStatus(ConstantPool.PaymentRequired);
            returnMsg.setMsg(Msg);
            return returnMsg;
        }

        String location=codeIdeInfo.getInfo().getLocation();
        if(location==null || location.equals("")){
            log.warn("获取用户路径失败!location:{}",location);
            Msg.add("获取用户容器路径失败!");
            returnMsg.setStatus(ConstantPool.BadRequest);
            returnMsg.setMsg(Msg);
            return returnMsg;
        }
        returnMsg.setLocation("/codeide/"+location);
        returnMsg.setMsg(Msg);
        return returnMsg;
    }

    @Override
    public CodeIdeReturnMsg registerCodeIde(CodeIdeInfo info) {
        CodeIdeReturnMsg returnMsg = new CodeIdeReturnMsg();
        List<String> Msg = new ArrayList<>();
        log.info("即将注册codeide.info:{}",info);
        UserAuthDataManagerReturnMsg userAuthDataByToken = authDataManagerAPI.getUserAuthDataByToken(info.getToken());
        log.info("通过token获取到用户信息:{}",userAuthDataByToken);
        if(userAuthDataByToken==null || !userAuthDataByToken.getStatus().equals(ConstantPool.OK)){
            log.warn("获取用户信息失败!返回信息:{}",userAuthDataByToken);
            returnMsg.setStatus(ConstantPool.BadRequest);
            Msg.add("获取用户信息失败!");
            returnMsg.setMsg(Msg);
            return returnMsg;
        }
        String uid = userAuthDataByToken.getAuthData().getUid();
        String port=getNewPort().toString();
        log.info("获取到用户uid:{}",uid);
        if(uid == null || uid.equals("")){
            log.warn("获取用户uid失败!uid:{}",uid);
            returnMsg.setStatus(ConstantPool.BadRequest);
            Msg.add("获取用户uid失败!");
            returnMsg.setMsg(Msg);
            return  returnMsg;
        }
        CodeIdeManagerReturnMsg codeIdeInfo = managerAPI.getCodeIdeInfo(uid);
        log.info("获取用户(uid:{})codeide信息:{}",uid,codeIdeInfo);
        if(codeIdeInfo.getStatus().equals(ConstantPool.OK)){
            log.info("获取到用户(uid:{})的codeide信息!",uid);
            Msg.add("该用户已存在codeide容器!请联系管理员!");
            returnMsg.setStatus(ConstantPool.BadRequest);
            returnMsg.setMsg(Msg);
            return returnMsg;
        }
        CodeIdeDispatchingCenterInfo userinfo= CodeIdeDispatchingCenterInfo.builder()
                .containerName(uid.substring(5))
                .location(uid)
                .password(info.getPassword())
                .port(port)
                .uid(uid)
                .build();
        String exchangeName="CodelabCreaters";
        String routingKey="createCodeIde";
        log.info("即将将信息发送到消息队列.");
        rabbitTemplate.convertAndSend(exchangeName,routingKey,userinfo);
        log.info("消息发送到消息队列.exchange:{},routingKey:{},userinfo:{}",exchangeName,routingKey,userinfo);
        managerAPI.setCodeIdePassword(new CodeIdeAccount(userinfo.getUid(), userinfo.getPassword()));
        log.info("用户信息存入到数据库.uid:{},password:{}",userinfo.getUid(),userinfo.getPassword());
        returnMsg.setLocation(userinfo.getLocation());
        returnMsg.setMsg(Msg);
        return returnMsg;
    }

    @Override
    public CodeIdeReturnMsg loginCodeIdeByToken(String ticket, String token) {
        CodeIdeReturnMsg returnMsg = new CodeIdeReturnMsg();
        List<String> Msg = new ArrayList<>();
        HttpHeaders headers = new HttpHeaders();
        headers.add("Authorization",token);
        log.info("即将通过token,ticket向省服务器验证token.ticket:{},token:{}",ticket,token);
        ResponseEntity<CodeIdeInventedPlatformTokenEntity> forEntity = restTemplate.getForEntity(baseUrl + "/api/OpenData/CheckToken", CodeIdeInventedPlatformTokenEntity.class,new HttpEntity<String>(headers));
        if (!forEntity.getStatusCode().is2xxSuccessful()){
            log.warn("请求未能成功!返回状态码为:{}",forEntity.getStatusCode());
            returnMsg.setStatus(500);
            Msg.add("未能正确向远程服务器发送请求!");
            returnMsg.setMsg(Msg);
            return returnMsg;
        }
        CodeIdeInventedPlatformTokenEntity body = forEntity.getBody();
        if (body==null){
            log.warn("未能正确获取响应体,返回为空!");
            returnMsg.setStatus(500);
            Msg.add("未能正确获取响应体！");
            returnMsg.setMsg(Msg);
            return returnMsg;
        }
        if (!body.getSuccess()){
            log.warn("验证失败!返回信息:{}",body.getMsg());
            returnMsg.setStatus(500);
            Msg.add("验证失败!");
            returnMsg.setMsg(Msg);
            return returnMsg;
        }
        log.info("验证成功!");
        returnMsg.setStatus(200);
        returnMsg.setMsg(Msg);
        return returnMsg;
    }

    private Integer getNewPort(){
        Random rad = new Random();
        List<String> allPorts = managerAPI.getAllPorts();
        Integer port;
        do {
            port = rad.nextInt(65535 - 10000) + 10000;
        } while (hasPort(allPorts,port));
        return port;
    }

    private Boolean hasPort(List<String> allPorts,Integer port){
        for(int i = 0;i<allPorts.toArray().length;i++){
            if (allPorts.get(i).equals(port.toString())){
                return true;
            }
        }
        return false;
    }

}

